Ayudantía 3 - Curso métodos en Ciencias Sociales Computacionales
Tutorial: Introducción a la ciencia de redes con R e igraph
En este tutorial, cubriremos los conceptos básicos de Network Science con R y el paquete igraph. Exploraremos los fundamentos de las redes, incluida la estructura y la dinámica de la red.
Introducción a Redes Complejas y Teoría de Grafos
Las redes complejas son sistemas compuestos por muchos elementos interconectados. Se encuentran en muchos sistemas naturales y artificiales, como Internet, redes sociales, redes celulares y redes de transporte. La teoría de grafos es la herramienta matemática utilizada para estudiar y analizar redes complejas. Los grafos están compuestos por nodos y aristas, que representan los elementos y conexiones de la red. La teoría de grafos permite el análisis de la estructura, la dinámica y la evolución de la red.
Elementos de una Red: Nodos y Aristas
En la teoría de grafos, una red se representa como un grafo, que se compone de nodos (también conocidos como vértices) y enlaces (también llamados bordes o aristas).
Los nodos representan los elementos de la red, como personas en una red social o ciudades en una red de transporte. Los bordes representan las conexiones entre nodos, como las relaciones entre personas o carreteras que conectan ciudades.
Cargando igraph y creando una primera red
# Cargando igraphlibrary(igraph)# Creando una primera red simple mediante fórmulanet <-graph.formula(A--B, B--C, C--D, D--E, E--F, F--G, G--A)# Imprimiendo el output de la red en igraph:net
Es posible también crear una red vacía y luego ir llenándola con nodos y enlaces
# Crear un grafo de red vacíog <-graph.empty() # Agregar vértices al grafog <-add.vertices(g, 5) # Agregar links al grafog <-add.edges(g, c(1,2, 1,3, 1,4, 1,5))
El paquete igraph tiene un módulo para graficar que está escrito sobre el paquete plot del base R. Por lo tanto, podemos obtener rápidamente una visualización de estas redes.
plot(net)
plot(g)
Propiedades de Redes y sus elementos
Número de nodos y de enlaces:
Número de nodos, o \(N\), representa el número de componentes en el sistema. A menudo llamaremos a N el tamaño de la red. Para distinguir los nodos, los etiquetamos con i = 1, 2, ..., N.
Número de enlaces, que denotamos con \(L\), representa el número total de interacciones entre los nodos. Los enlaces rara vez están etiquetados, ya que pueden identificarse a través de los nodos que conectan. Por ejemplo, el enlace (2, 4) conecta los nodos 2 y 4.
Redes dirigidas y no dirigidas
Una de las más básicas es la diferenciación entre redes dirigidas o redes no dirigidas. En las redes no dirigidas, los enlaces no tienen dirección, lo que significa que la conexión entre dos nodos es simétrica, por ejemplo en una red de amistad en Facebook. En las redes dirigidas, los enlaces tienen una dirección, lo que significa que la conexión entre dos nodos es asimétrica, por ejemplo en redes de seguidores en Twitter.
¿Qué podemos decir de N y L en las redes anteriores? ¿y de la direccionalidad de ambas redes?
# en igraph podemos llamar separadamente a los nodos y los enlaces de un grafo.# para los nodos, podemos hacerV(net)
+ 7/7 vertices, named, from fd3c7ed:
[1] A B C D E F G
# por tanto, una forma de calcular el número de nodos N es haciendolength(V(net))
[1] 7
#o también con la función construida vcount(g)
[1] 5
# análogamente para los enlaceslength(E(net))
[1] 7
ecount(g)
[1] 4
# para ver si un grafo es dirigido o nois_directed(net)
[1] FALSE
is.directed(g)
[1] TRUE
Atributos
Las redes también pueden tener atributos asociados a los nodos y a los enlaces. Los atributos de nodo son características asociadas con cada nodo, como la edad de una persona en una red social o la población de una ciudad en una red de transporte. Los atributos de enlace son características asociadas con cada enlace, como la fuerza de una relación entre dos personas en una red social o la distancia entre dos ciudades en una red de transporte.
Grado de un nodo
Una propiedad clave de cada nodo es su grado, que representa el número de enlaces que tiene con otros nodos. El grado puede representar la cantidad de contactos de teléfonos celulares que tiene una persona en un grafo de llamadas (es decir, la cantidad de personas diferentes con las que ha hablado la persona), la cantidad de citas que recibe un paper en una red de citaciones académicas, o como en los ejemplos anteriores, la cantidad de amigos que tiene una persona en facebook, o la cantidad de vuelos que llegan y/o que salen de un aeropuerto en una red dirigida de transporte aéreo de pasajeros. Usualmente se denomina con \(k_i\) el grado del i-esimo nodo de la red.
En una red no dirigida, el número total de enlaces \(L\), se puede expresar como la suma de los grados de los nodos:
\[L = \frac{1}{2} \sum_{i=1}^N k_i \] Donde el factor \(\frac{1}{2}\) está corrigiendo el hecho que en la sumatoria cada enlace se esté contando dos veces.
Grado promedio de una red
Para una red no dirigida, el grado promedio está dado por:
\[ \langle k \rangle = \frac{1}{N} \sum_{i=1}^N k_i = \frac{2L}{N}\]
En redes dirigidas, como distinguimos entre in-degree de un nodo, donde \({k_i}^{in}\) representa el número de links que apuntan a un nodo \(i\), y out-degree\({k_i}^{out}\), representando el número de enlaces que apuntan desde el nodo \(i\) hacia otros nodos. Finalmente, el grado total de un nodo \(k_i\) en una red dirigida está dado por
\[ k_i = {k_i}^{in}+{k_i}^{out}\] Luego, el número total de enlaces de una red dirigida es: \[L = \sum_{i=1}^N {k_i}^{in} = \sum_{i=1}^N {k_i}^{out}\] No hay corrección por el factor de \(\frac{1}{2}\) ya que cada suma cuenta separadamente una vez cada enlace al contar “solo una punta” del enlace. El grado promedio de una red dirigida está dado por: \[ \langle k^{in} \rangle = \frac{1}{N} \sum_{i=1}^N {k_i}^{in} = \langle k^{out} \rangle = \frac{1}{N} \sum_{i=1}^N {k_i}^{out} = \frac{L}{N}\]
Distribución de grados
La distribución de grados, \(p_k\), provee la probabilidad que un nodo seleccionado al azar de la red tenga grado \(k\). Dado que \(p_k\) es una probabilidad, debe ser normalizada, i.e.
\[ \sum_{i=1}^{\infty} {p_k} = 1\]
La distribución de grados ha asumido un papel central en la teoría de redes tras el descubrimiento de las redes libres de escala. Una razón es que el cálculo de la mayoría de las propiedades de la red requiere que sepamos \(p_k\). Por ejemplo, el grado promedio de una red se puede escribir como:
\[ \langle k \rangle = \sum_{k=0}^\infty {k p_k} \] Otra razón para ello es que la forma funcional precisa de \(p_k\) determina muchos fenómenos de redes, desde la robustez de esta hasta la propagación de virus.
Peso o ponderación de un enlace:
En muchas aplicaciones, necesitamos modelar redes ponderadas, donde cada link \((i,j)\) tiene un peso único \(w_{ij}\). En una red de llamadas de celulares, por ejemplo, el peso puede representar el número total de minutos que dos sujetos hablaron por teléfono, o en una grilla de potencia, el peso es la cantidad de corriente que fluye a través de una línea de transmisión. Para redes con pesos, los elementos de la matriz de adyacencia tienen el peso del enlace, de esta forma:
\[ A_{ij} = w_{ij}\] En general, la mayoría de las redes de interés tiene pesos, pero no siempre podemos medirlos adecuadamente, y muchas de las métricas ya conocidas en redes sin pesos se vuelven más costosas computacionalmente o a veces incluso dejan de tener tanto sentido al agregar los pesos a la ecuación. Esto hace que muchas veces terminamos filtrando y aproximando estas redes con un grafo no ponderado.
Objetos de clase igraph
La descripción de un objeto de clase igraphparte con hasta cuatro letras:
D o U, para un gráfico dirigido o no dirigido N para un grafo con nombre (donde los nodos tienen un atributo de nombre) W para un grafo ponderado o con pesos (donde los enlaces tienen un atributo de peso) B para un grafo bipartito (dos modos) (donde los nodos tienen un atributo de tipo) Los dos números que siguen (7 5) se refieren al número de nodos y aristas en el gráfico. La descripción también enumera los atributos de nodo y borde, por ejemplo:
(g/c) - atributo de carácter a nivel de gráfico (v/c) - atributo de carácter de nivel de vértice (e/n) - atributo numérico de nivel de borde
# veamos el grado de cada nodo, y el grado promedio y distribución de grado para las redes g y netdegree(net)
A B C D E F G
2 2 2 2 2 2 2
degree.distribution(net)
[1] 0 0 1
Matriz de adyacencia
Es matematicamente posible y muchas veces conveniente en términos analíticos y computacionales poder representar una red a través de una Matriz de Adyacencia. La matriz de adyacencia de una red dirigida de \(N\) nodos tiene \(N\) filas y \(N\) columnas, siendo sus elementos:
\(A_{ij} = 1\) si hay un enlace que apunta desde el nodo \(j\) al nodo \(i\)
\(A_{ij} = 0\) si no es así.
La matriz de adyacencia de una red no dirigida tiene dos entradas para cada enlace, e.g. el enlace (1, 2) se representa como \(A_{12} = 1\) y \(A_{21} = 1\). Por lo tanto, la matriz de adyacencia de una red no dirigida es simétrica, \(A_{ij} = A_{ji}\)
El grado \(k_i\) del nodo \(i\) se puede obtener directamente de los elementos de la matriz de adyacencia. Para redes no dirigidas, el grado de un nodo es una suma sobre las filas o las columnas de la matriz, es decir
\[ k_i = \sum_{j=1}^N {A_{ji}} = \sum_{j=1}^N {A_{ij}} \] Para redes dirigidas, las sumas sobre las filas y columnas de la matriz de adyacencia proporcionan los grados entrantes y salientes, respectivamente.
Dado que en una red no dirigida el número de enlaces salientes es igual al número de enlaces entrantes, tenemos \[2L = \sum_{i=1}^N {k_{i}}^{in} = \sum_{i=1}^N {k_{i}}^{out} =\sum_{ij}^N {A_{ij}} \]
El número de elementos distintos de cero de la matriz de adyacencia es 2L, o el doble del número de enlaces. De hecho, un enlace no dirigido que conecta los nodos \(i\) y \(j\) aparece en dos entradas: \(A_{ij} = 1\), un enlace que apunta del nodo \(j\) al nodo \(i\), y \(A_{ji} = 1\), un enlace que apunta del \(i\) al \(j\)
ejemplo un poco más complejo
Veamos la siguiente red
g4 <-graph( c("John", "Jim", "Jim", "Jack", "Jim", "Jack", "John", "John"), isolates=c("Jesse", "Janis", "Jennifer", "Justin") ) # Se pueden especificar los nodos aislados con una lista.
# En general, se pueden llamar colores por el nombre, el código hexadecimal y por los valores rgb# e.g. "blue" "dark red" "#557799" or rgb(.25, .5, .3))# Podemos ver los nombres de colores default con colors():colors()
# Ya vimos que podíamos acceder a los vértices y enlaces medianteE(g4) # Enlaces
+ 4/4 edges from 3b51b7d (vertex names):
[1] John->Jim Jim ->Jack Jim ->Jack John->John
V(g4) # Vértices
+ 7/7 vertices, named, from 3b51b7d:
[1] John Jim Jack Jesse Janis Jennifer Justin
# Se puede examinar la matriz de la red directamente también medianteg4[] # la matriz de adyacencia completa (de tipo sparse para gastar menos memoria)
7 x 7 sparse Matrix of class "dgCMatrix"
John Jim Jack Jesse Janis Jennifer Justin
John 1 1 . . . . .
Jim . . 2 . . . .
Jack . . . . . . .
Jesse . . . . . . .
Janis . . . . . . .
Jennifer . . . . . . .
Justin . . . . . . .
g4[1,] # la fila de John
John Jim Jack Jesse Janis Jennifer Justin
1 1 0 0 0 0 0
# Podemos llamar y añadir/quitar atributos a la red, los vértices y los enlaces haciendo:V(g4)$name # Se genera automáticamente cuando se crea la red.
V(g4)$gender <-c("male", "male", "male", "male", "female", "female", "male") E(g4)$type <-"email"# Atributo de enlace, asignado "email" para todos los enlaces.E(g4)$weight <-10# Atributo de peso, asignandole peso 10 a todos los enlaces existentes.
# Examinemos los atributos# de los enlacesedge_attr(g4)
# Otra forma de settear atributos# Análogamente se puede usar set_edge_attr() y set_vertex_attr(), así como get.edge.attribute(), etc.g4 <-set_graph_attr(g4, "name", "Email Network") g4 <-set_graph_attr(g4, "something", "A thing")graph_attr_names(g4)
[1] "name" "something"
graph_attr(g4, "name")
[1] "Email Network"
graph_attr(g4)
$name
[1] "Email Network"
$something
[1] "A thing"
# g4 tiene dos aristas que van de Jim a Jack y un bucle de John a él mismo.# Podemos simplificar nuestro gráfico para eliminar bucles y múltiples bordes entre los mismos nodos.# Usamos 'edge.attr.comb' para indicar cómo se combinarán los atributos de enlace - posibles# opciones incluyen "suma", "media", "prod" (producto), min, max, primero/último (selecciona# el atributo del primer/último enlace). La opción "ignorar" dice que el atributo debe ser# ignorado y descartado.g4s <-simplify( g4, remove.multiple = T, remove.loops = F, edge.attr.comb=list(weight="sum", type="ignore") )plot(g4s, vertex.label.dist=1.5)
g4s
IGRAPH e7b0b61 DNW- 7 3 -- Email Network
+ attr: name (g/c), name (v/c), gender (v/c), weight (e/n)
+ edges from e7b0b61 (vertex names):
[1] John->John John->Jim Jim ->Jack
Centralidad
Las medidas de centralidad se utilizan para identificar los nodos más importantes de una red. Las medidas de centralidad más utilizadas son la centralidad de grado, la centralidad de intermediación y la centralidad de cercanía. La centralidad de grado mide la cantidad de conexiones que tiene un nodo, la centralidad de intermediación mide la cantidad de rutas más cortas en las que se encuentra un nodo y la centralidad de cercanía mide la distancia promedio de un nodo a todos los demás nodos en la red.
# Calcular índices de red# Calcular grado de centralidad (degree centrality) degree_centrality <-degree(g) # Calcular centralidad de cercanía closeness_centrality <-closeness(g) # Calcular la centralidad de intermediaciónbetweenness_centrality <-betweenness(g)# Analiza el grafo de red# Calcular la transitividad del grafo de redtransitivity <-transitivity(g, type ='global') # Calcular la longitud de ruta promedio entre nodosavg_path_length <-average.path.length(g) # Calcular la densidad de la reddensity <-graph.density(g)
Leyendo datos de redes
1. Datos como edgelist: DATASET 1
nodes <-read.csv("data/Dataset1-Media-Example-NODES.csv", header=T, as.is=T)links <-read.csv("data/Dataset1-Media-Example-EDGES.csv", header=T, as.is=T)# Examinamos la datahead(nodes)
id media media.type type.label audience.size
1 s01 NY Times 1 Newspaper 20
2 s02 Washington Post 1 Newspaper 25
3 s03 Wall Street Journal 1 Newspaper 30
4 s04 USA Today 1 Newspaper 32
5 s05 LA Times 1 Newspaper 20
6 s06 New York Post 1 Newspaper 50
# Colapsamos multiples links del mismo tipo entre los mismos dos nodos sumando sus pesos, # usaremos aggregate() (del base R), usando by "from", "to", y "type":# No usamos "simplify()" acá, para no colapsar los distintos tipos de enlaces.links <-aggregate(links[,3], links[,-3], sum)links <- links[order(links$from, links$to),]colnames(links)[4] <-"weight"rownames(links) <-NULL
Creando objetos de igraph
library(igraph)# --- DATASET 1 # Convirtiendo los datos a un objeto de igraph:# La función graph.data.frame, que toma dos data frames: 'd' y 'vertices'.# 'd' describe los enlaces de la red - Debería empezar con dos columnas que contengan # los ID's del emisor (source) y el receptor (target) para cada enlace.# 'vertices' debería comenzar con una columna de ID de los nodos# Cada columna adicional en cada data frame es interpretado como atributos de los enlaces y de los nodos respectivamente.net <-graph_from_data_frame(d=links, vertices=nodes, directed=T) # Veamos el objeto que resultaclass(net)
name media media.type type.label audience.size
s01 s01 NY Times 1 Newspaper 20
s02 s02 Washington Post 1 Newspaper 25
s03 s03 Wall Street Journal 1 Newspaper 30
s04 s04 USA Today 1 Newspaper 32
s05 s05 LA Times 1 Newspaper 20
s06 s06 New York Post 1 Newspaper 50
s07 s07 CNN 2 TV 56
s08 s08 MSNBC 2 TV 34
s09 s09 FOX News 2 TV 60
s10 s10 ABC 2 TV 23
s11 s11 BBC 2 TV 34
s12 s12 Yahoo News 3 Online 33
s13 s13 Google News 3 Online 23
s14 s14 Reuters.com 3 Online 12
s15 s15 NYTimes.com 3 Online 24
s16 s16 WashingtonPost.com 3 Online 28
s17 s17 AOL.com 3 Online 33
Graficando redes con igraph
# Ploteando con igraph:# opciones de nodos: argumento partiendo con `vertex.`# opciones de enlaces: argumento partiendo con `edge.`# Acá podemos ver una lista de opciones?igraph.plotting
# Podemos setear las node & edge options de dos formas: una es especificarlas en el argumento de plot(), por ejemplo:# Plot con edges curvos (edge.curved=.1) y el tamaño de la flecha reducido:plot(net, edge.arrow.size=.4, edge.curved=.1)
# Seteamos el color del nodo a naranjo y el color del borde a hex #555555# Reemplazamos las etiquetas de los vértices con los nombres de los nodos que están almacenados en el atributo "media".plot(net, edge.arrow.size=.2, edge.curved=0,vertex.color="orange", vertex.frame.color="#555555",vertex.label=V(net)$media, vertex.label.color="black",vertex.label.cex=.7)
# La segunda manera de setear atributos que modifiquen el plot es añadírselo al objeto de igraph.# Generar colores basados en "media.type":colrs <-c("gray50", "tomato", "gold")V(net)$color <- colrs[V(net)$media.type]# Seteamos el tamaño del nodo basado en el tamaño de la audiencia:V(net)$size <-V(net)$audience.size*0.7# Los labels en este momento son los IDs de los nodos.# Si los seteamos a NA, el gráfico no va a mostrar lables:V(net)$label.color <-"black"V(net)$label <-NA# Seteamos el ancho de los enlaces basados en el peso:E(net)$width <-E(net)$weight/6#Cambiamos el tamaño de la flecha y el color de la arista:E(net)$arrow.size <- .2E(net)$edge.color <-"gray80"# Podemos setear también el layout de la red:graph_attr(net, "layout") <- layout_with_lglplot(net)
# Podemos también pasar por sobre los atributos al usar el argumento explícito en el plot:plot(net, edge.color="orange", vertex.color="gray50")
# Podemos también añadir una leyenda explicando el significado de los colores que usamos:plot(net) legend(x=-1.1, y=-1.1, c("Newspaper","Television", "Online News"), pch=21,col="#777777", pt.bg=colrs, pt.cex=2.5, bty="n", ncol=1)
# A veces, especialmente con redes semánticas, podemos estar interesados en plotear solo los labels de los nodos:plot(net, vertex.shape="none", vertex.label=V(net)$media, vertex.label.font=2, vertex.label.color="gray40",vertex.label.cex=.7, edge.color="gray85")
# Podemos añadir color a los enlaces del grafo basados en el color del nodo emisor o source# Vamos a obtener el nodo de comienzo para cada enlace con "ends()".edge.start <-ends(net, es=E(net), names=F)[,1]edge.col <-V(net)$color[edge.start]plot(net, edge.color=edge.col, edge.curved=.1)
Layouts y algoritmos de visualización de redes.
Existen muchas formas de visualizar una red. Los grafos se pueden visualizar como nodos y aristas, o como matrices, que muestran las conexiones entre los nodos. Los grafos también se pueden visualizar mediante diagramas de red, que muestran la estructura de la red como una serie de nodos interconectados. Existen muchos layouts de redes, que son algoritmos que al computarse, retornan coordenadas para cada nodo (y cada enlace) en una red.
# Generemos un grafo relativamente largo de 80 nodos.net.bg <-sample_pa(80, 1.2) V(net.bg)$size <-8V(net.bg)$frame.color <-"white"V(net.bg)$color <-"orange"V(net.bg)$label <-""E(net.bg)$arrow.mode <-0plot(net.bg)
# Se puede settear el layout en la función plot:plot(net.bg, layout=layout_randomly)
# O también calcular las coordenadas de los vértices por adelantado:l <-layout_in_circle(net.bg) # un nuevo layoutplot(net.bg, layout=l)
# l es simplemente una matriz de coordenadas x,y (N x 2) para los N nodos en el grafo# Puedes generar una propia:l
l <-cbind(1:vcount(net.bg), c(1, vcount(net.bg):2))plot(net.bg, layout=l)
# Este layout no sirve mucho...# En todo caso, igraph trae un buen número de layouts, entre los cuales están# vértices al azarl <-layout_randomly(net.bg)plot(net.bg, layout=l)
# layout esfera 3D l <-layout_on_sphere(net.bg)plot(net.bg, layout=l)
# Fruchterman-Reingold force-directed algorithm # Bueno, pero lento de computar, usualmente para grafos de no más de 1000 nodos l <-layout_with_fr(net.bg)plot(net.bg, layout=l)
# Los layouts no son deterministicos: varían ligeramente cada vez que se corren. # Si guardamos las coordenadas l, podemos reproducir la misma figura varias veces.par(mfrow=c(2,2), mar=c(1,1,1,1))plot(net.bg, layout=layout_with_fr)plot(net.bg, layout=layout_with_fr)plot(net.bg, layout=l)plot(net.bg, layout=l)
dev.off()
null device
1
# Por default, las coordenadas de los gráficos son reescaladas al intervalo [-1,1]# para x e y. Se puede cambiar esto con el parámetro "rescale=FALSE".# y reescalarlo manualmente multiplicando las coordenadas por un escalar. # Se puede usar norm_coords para normalizar el plot con los bordes que se requieran.# Extraer las coordenadas del layout:l <-layout_with_fr(net.bg)# Normalizarlas para que queden en el intervalo -1, 1:l <-norm_coords(l, ymin=-1, ymax=1, xmin=-1, xmax=1)par(mfrow=c(2,2), mar=c(0,0,0,0))plot(net.bg, rescale=F, layout=l*0.4)plot(net.bg, rescale=F, layout=l*0.8)plot(net.bg, rescale=F, layout=l*1.2)plot(net.bg, rescale=F, layout=l*1.6)
dev.off()
null device
1
# Otro algoritmo force-directed popular que da buenos resultados para grafos conectados es Kamada Kawai. Como el Fruchterman Reingold, intenta minimizar la energía en un sistema de resortes.l <-layout_with_kk(net.bg)plot(net.bg, layout=l)
# El algoritmo LGL es para grafos largos conectados. Aquí se puede especificar un root - el nodo que se pondrá en el medio del layout.plot(net.bg, layout=layout_with_lgl)
# Por default, igraph usa un layout llamado layout_nicely, que selecciona# un layout apropiado basado en las propiedades del grafo.# Chequea todos los layouts disponibles en igraph:?igraph::layout_layouts <-grep("^layout_", ls("package:igraph"), value=TRUE)[-1] # Remueve todos los layouts que no apliquen al grafo:layouts <- layouts[!grepl("bipartite|merge|norm|sugiyama|tree", layouts)]par(mfrow=c(3,3), mar=c(1,1,1,1))for (layout in layouts) {print(layout) l <-do.call(layout, list(net)) plot(net, edge.arrow.mode=0, layout=l, main=layout) }
[1] "layout_as_star"
[1] "layout_components"
[1] "layout_in_circle"
[1] "layout_nicely"
[1] "layout_on_grid"
[1] "layout_on_sphere"
[1] "layout_randomly"
[1] "layout_with_dh"
[1] "layout_with_drl"
[1] "layout_with_fr"
[1] "layout_with_gem"
[1] "layout_with_graphopt"
[1] "layout_with_kk"
[1] "layout_with_lgl"
[1] "layout_with_mds"
dev.off()
null device
1
Redes aleatorias, de mundo pequeño y libres de escala (solo un vistazo)
Las redes aleatorias son redes en las que las conexiones entre nodos se generan aleatoriamente. Las redes aleatorias son útiles para analizar la estructura y la dinámica de las redes y, a menudo, se utilizan para modelar redes del mundo real.
# Erdos-Renyi random graph # ('n' es el número de nodos, 'm' es el número de enlaces)er <-sample_gnm(n=100, m=40) plot(er, vertex.size=6, vertex.label=NA)
# Watts-Strogatz small-world graph# Creamos un lattice con 'dim' dimensiones de 'size' nodes cada uno, y recableamos los enlaces aleatoriamente con probabilidad 'p'. Podemos permitir 'loops' y enlaces 'multiples'.# El neighborhood en el cual los enlaces estaban conectados es 'nei'.sw <-sample_smallworld(dim=2, size=10, nei=1, p=0.1)plot(sw, vertex.size=6, vertex.label=NA, layout=layout_in_circle)
# Modelo de preferencial attachment de Barabasi-Albert preferential attachment para redes de escala libre# 'n' es el número de nodos, 'power' es la "potencia" del attachment (1 es linear)# 'm' es el número de enlaces añadidos en cada paso de tiempo ba <-sample_pa(n=100, power=1, m=1, directed=F)plot(ba, vertex.size=6, vertex.label=NA)
# También podemos llamar algunas redes clásicas: El club de Karate de Zachary zach <-graph("Zachary") # Zachary Karate clubplot(zach, vertex.size=10, vertex.label=NA)
# Y también otros grafos con alguna característica notable. Por ejemplo, un treetr <-make_tree(40, children =3, mode ="undirected")plot(tr, vertex.size=10, vertex.label=NA)
# O un grafo full, donde todos estén enlazados con todosfg <-make_full_graph(40)plot(fg, vertex.size=10, vertex.label=NA)
# "Recableando" un grafo# creamos primero un grafo de tipo anillo:rn <-make_ring(40)plot(rn, vertex.size=10, vertex.label=NA)
# 'each_edge()' es un método de rewiring que cambia el endpoint de los enlaces# de manera uniformemente aleatoria con una probabilidad 'prob'.rn.rewired <-rewire(rn, each_edge(prob=0.1))plot(rn.rewired, vertex.size=10, vertex.label=NA)
# Rewire para conectar los vértices a otros vértices a una cierta distancia. rn.neigh =connect.neighborhood(rn, 5)plot(rn.neigh, vertex.size=8, vertex.label=NA)
Cargamos el paquete igraphdata, donde vienen varios ejemplos de redes reales de distinto tipo.
library(igraphdata)help(igraphdata)
Redes Bipartitas
Las redes bipartitas son redes en las que los nodos se pueden dividir en dos conjuntos distintos, como personas y organizaciones en una red social o universidades y estudiantes en una red educativa. Las redes bipartitas son útiles para analizar las relaciones entre dos tipos diferentes de elementos.
Datos de una red bipartita en una matriz: DATASET 2
library(igraph)nodes2 <-read.csv("data/Dataset2-Media-User-Example-NODES.csv", header=T, as.is=T)links2 <-read.csv("data/Dataset2-Media-User-Example-EDGES.csv", header=T, row.names=1)# Examinamos la datahead(nodes2)
# links2 es la matriz de incidencia para una two-mode network:links2 <-as.matrix(links2)dim(links2)
[1] 10 20
dim(nodes2)
[1] 30 5
net2 <-graph_from_incidence_matrix(links2)# Un atributo de los vértices 'type' muestra a qué modo/tipo pertenece cada vértice.table(V(net2)$type)
FALSE TRUE
10 20
plot(net2,vertex.label=NA)
# Para transformar una matriz de una red de un modo a un objeto de igraph, podemos usar la función# graph_from_adjacency_matrix()# También podemos generar fácilmente las proyecciones bipartitas para redes de dos modos:# (Las Co-membresías son fáciles de calcular, multiplicando la matriz de la red por su traspuesta, o usando la función de igraph `bipartite.projection`)net2.bp <-bipartite.projection(net2)
# Se pueden calcular las proyecciones de manera manual también:# as_incidence_matrix(net2) %*% t(as_incidence_matrix(net2))# t(as_incidence_matrix(net2)) %*% as_incidence_matrix(net2)
Ejemplo extendido: Flavor Network and the Principles of Food Pairing.
El paper “Flavor Network and the Principles of Food Pairing” aplica la ciencia de redes y otras técnicas de análisis de datos para construir una red de sabores a partir de una gran base de datos de recetas. Específicamente, los autores construyen una red dirigida y ponderada en la que los nodos representan ingredientes individuales y los bordes representan el grado en que los ingredientes se usan juntos en las recetas. Luego, los autores analizan la red para identificar los principios subyacentes al maridaje de alimentos.
Los principales métodos utilizados en esta investigación incluyen la minería de datos y el análisis de redes. Los autores extraen una gran base de datos de recetas para obtener los ingredientes utilizados en cada receta y el grado en que se utilizan juntos. Estos datos se utilizan luego para construir la red de sabor. Luego se emplean técnicas de análisis de redes para identificar los patrones de combinaciones de ingredientes y los principios que los sustentan.
Los principales resultados de esta investigación incluyen la identificación de cuatro principios de maridaje de alimentos. Estos principios son emparejamientos complementarios (p. ej., sweet-sour), compartir ingredientes (p. ej., huevos y leche), ingredientes puente (p. ej., cebollas) y afinidades de sabor (p. ej., ajo y albahaca). Los autores también identificaron una serie de ingredientes específicos que se usan comúnmente para unir diferentes perfiles de sabor.
Los conceptos de ciencia de redes aplicados en esta investigación incluyen el análisis de topología de red y redes ponderadas. Los autores analizan la topología de la red para identificar los patrones de emparejamiento de ingredientes y los principios que los sustentan. También analizan la red ponderada para identificar los ingredientes que comúnmente se usan juntos.
Leer datos
Los datos de Flavor Network están disponibles en el sitio web http://www.nature.com/articles/srep00196#data. Este conjunto de datos contiene una lista de ingredientes y sus compuestos de sabor asociados.
# leemos los datos descargadosedgelist_net_1=read.csv(file ="data/srep00196-s2.csv",skip =4, header = F)edgelist_net_2 =read.csv(file ="data/srep00196-s3.csv",skip =4, header = F)
¿Qué son estas redes? ¿Son los datos “crudos”, o los datos ya procesados?